<?php

/**
 * 拼多多对接(云外调用订单接口)
 * @date 20210618
 * @author chenshubo
 */
namespace App\Service\VendorClient\PddApi;

use App\Model\PssLogModel\MicroServiceLog;
use App\Model\PssModel\Business;
use App\Model\PssModel\OrderPullLog;
use App\Service\BaseService;
use App\Service\Code\Normal;
use App\Service\HttpRequest\Http;

class ShopOutCloundPddApiClient extends BaseService
{
    protected $config;
    protected $account;
    protected $bid;
    protected $client_id;
    protected $client_secret;
    protected $access_token;
    protected $extends;
    protected $shop;
    protected $url = 'https://gw-api.pinduoduo.com/api/router';
    protected $routeMap = [
        'getAccessToken'    => 'pdd.pop.auth.token.create',
        'getMallInfo'       => 'pdd.mall.info.get',
        'getOrderList'      => 'pdd.order.list.get',
        'getClearAnceInfo'  => 'pdd.oversea.clearance.get',
        'getOrderInfo'      => 'pdd.order.information.get',
        'updateGoods'       => 'pdd.goods.quantity.update',
        'addGoods'          => 'pdd.goods.edit.goods.commit',
        'uploadImg'         => 'pdd.goods.image.upload',
        'decrypt'           => 'pdd.open.decrypt.batch',
        'orderExpress'      => 'pdd.logistics.online.send',
        'orderCancel'       => 'pdd.order.number.list.increment.get',
        'waybillget'        => 'pdd.waybill.get',
        'waybillsearch'     => 'pdd.waybill.search',
        'waybillReturn'     => 'pdd.fds.waybill.return',
        'orderlogisticget'  => 'pdd.logistics.ordertrace.get',
        'goodsSaleStatusSet'=> 'pdd.goods.sale.status.set'
    ];
    public function __construct( $shop = null )
    {
        $extends = @json_decode($shop['extends'],true);
        $this->client_id                = $extends['client_id'];
        $this->client_secret            = $extends['client_secret'];
        $this->shop                     = $shop;
        $this->bid                      = $shop['bid'];
        $this->access_token             = $shop['token'];
        $this->extends                  = $extends;
    }
    
    /**
     * 拉取订单
     * @param array $params
     * @return mixed
     */
    public function queryOrderList($param = []) 
    {
        $page = isset($param['page']) ? $param['page'] : 1 ;
        $data = [
            'order_status'      =>  5,
            'refund_status'     =>  1,
            'start_confirm_at'  =>  $param['time'] - $this->extends['interval_time'],
            'end_confirm_at'    =>  $param['time'],
            'page'              =>  $page,
            'page_size'         =>  100,
            'use_has_next'      =>  'true'
        ];
        $parameter = [
            'method'    => 'getOrderList',
            'data'      => $data,
        ];
        $res =$this->execute($parameter);
        if( $res['code'] != Normal::SUC )  {
            return $res;
        }
        
        $list = $res['data'];
        if( empty($list) || empty($list['order_list_get_response']['order_list']) ) {
            return Normal::returnCode(Normal::SUC,"请求成功，无订单");
        }
        
        $order_list_get_response = $list['order_list_get_response'];
        $order_list = $order_list_get_response['order_list'];
        
        //循环获取电子面单数据
        foreach ($order_list as $orderInfo )
        {
            $order_sn   = $orderInfo['order_sn'];
            $item_list  = $orderInfo['item_list'];
            //组装添加记录
            $addPullOrderLog = [
                'bid'           => $this->bid,
                'order_sn'      => $order_sn,
                'contents'      => json_encode($orderInfo,JSON_UNESCAPED_UNICODE),
            ];
            //写入pdd捞单池日志
            OrderPullLog::instance()->addLog($addPullOrderLog);
        }
        
        if( $order_list_get_response['has_next'] ) {
            $this->queryOrderList(['page'=>$param['page']+1,'time'=>$param['time']]);
        }
        
        return Normal::returnCode(Normal::SUC,"处理完成");
    }
    
    /**
     * 解密数据
     * @param array $order_list
     * @return mixed
     */
    public function decryptData(array $order_list)
    {
        $decrpt_fields = [
            'receiver_phone',
            'receiver_address',
            'address',
            'receiver_name',
        ];
        $enData = [];
        foreach ($order_list as $k => $v )
        {
            $order_sn = $v['order_sn'];
            $in = [];
            foreach ($decrpt_fields as $field)
            {
                $in[] = [
                    'data_tag'          => $order_sn,
                    'encrypted_data'    => $v[$field]
                ];
            }
            $enData=array_merge($enData,$in);
        }
        $parameter = [
            'method' => 'decrypt',
            'data'   => [
                'data_list' => json_encode($enData)//1、虚拟卡密;2、虚拟卡号;3、支付商品编码;4、支付单号;5、收件人;6、收件人手机号;7、收件人完整地址;8、收件人详细地址;9、快递单号;10、身份证号;11、身份证姓名
            ],
        ];
        return $this->execute($parameter);
    }
    
    /**
     * 获取guid 信息
     * @return string
     */
    public function guid()
    {
        mt_srand((double)microtime()*10000);
        $charid = strtoupper(md5(uniqid(rand(), true)));
        $hyphen = chr(45);// "-"
        $uuid = substr($charid, 0, 8).$hyphen
        .substr($charid, 8, 4).$hyphen
        .substr($charid,12, 4).$hyphen
        .substr($charid,16, 4).$hyphen
        .substr($charid,20,12);
        return $uuid;
    }

    /**
     * 上传图片
     */
    public function uploadImg($img)
    {
        $imageInfo = getimagesize($img);
        $data = [
            'image' => 'data:' . $imageInfo['mime'] . ';base64,' . chunk_split(base64_encode(file_get_contents($img)))
        ];
        $parameter = [
            'method'    => 'uploadImg',
            'data'      => $data
        ];
        $res = $this->execute($parameter);
        return $res['data']['goods_image_upload_response']['image_url']??'';
    }
    
    /**
     * 添加草稿箱商品
     * @param array $param
     */
    public function addGoods( array $goodsInfo = [] ) 
    {
        $skuinfo    = current($goodsInfo['skuList']);
        $storeList  = current($skuinfo['storeList']);
        $batch_info = current($storeList['goods_batch_list']);
        $skucode    = $skuinfo['skucode'];
        /* $pattern="/<img.*?src=[\'|\"](.*?)[\'|\"].*?[\/]?>/";
        preg_match_all($pattern,htmlspecialchars_decode($goodsInfo['description']),$match);
        if(!empty($match[1])){
            $body=$match[1];
        }else{
            return Normal::returnCode(Normal::FAIL,"详情图片不存在");
        } */
        $newBody[] = $this->uploadImg($goodsInfo['images'][0]);
        /* $newBody=[];
        foreach ($body as $v){
            $img=$this->uploadImg($v);
            if($img){
                $newBody[]=$img;
            }
        } */
        
        $data = [
            'cat_id'         => 18491,
            'out_goods_id'   => $skucode,
            'goods_name'     => $goodsInfo['goodsName'],
            'detail_gallery' => json_encode($newBody),//详情图
        ];
        $parameter = [
            'method'    => 'addGoods',
            'data'      => $data
        ];
        return $this->execute($parameter);
    }
    
    /**
     * 更新商品
     * @param array $goodsInfo
     * @param array $pddGoods
     */
    public function updateGoods( array $goodsInfo ,array $pddGoods)
    {
        $skuinfo    = current($goodsInfo['skuList']);
        $storeList  = current($skuinfo['storeList']);
        $batch_info = current($storeList['goods_batch_list']);
        $skucode    = $skuinfo['skucode'];
        $data = [
            'goods_id'  => $pddGoods['pdd_goods_id'],
            'outer_id'  => $skucode,
            'quantity'  => $batch_info['num'],
        ];
        $parameter = [
            'method'    => 'updateGoods',
            'data'      => $data
        ];
        return $this->execute($parameter);
    }

    /**
     * 物流订单发货
     */
    public function orderExpress( $param=[] )
    {
        if( empty($param['orderInfo']) || empty($param['express'])) {
            return Normal::returnCode(Normal::FAIL,"except param express or orderInfo");
        }
        $express    = $param['express'];
        $orderInfo  = $param['orderInfo'];
        if( empty($express['expressCode']) ) {
            return Normal::returnCode(Normal::FAIL,"except param expressCode");
        }
        if( empty($express['expressNo']) ) {
            return Normal::returnCode(Normal::FAIL,"except param expressNo");
        }
        if( empty($orderInfo['order_sn']) ) {
            return Normal::returnCode(Normal::FAIL,"except param order_sn");
        }
        
        $data = [
            'tracking_number'   => $express['expressNo'],
            'order_sn'          => $orderInfo['order_sn'],
            'logistics_id'      => $express['expressCode'],
        ];
        $parameter = [
            'method'    => 'orderExpress',
            'data'      => $data
        ];
        $res = $this->execute($parameter);
        if($res['code']==Normal::SUC){
            $is_success= $res['data']['logistics_online_send_response']['is_success'];
            if($is_success){
                return Normal::returnCode(Normal::SUC,"发货成功");
            }else{
                return Normal::returnCode(Normal::FAIL,"发货失败");
            }
        }
        
        //异常发货处理
        if( isset($res['data']['error_response']['sub_code']) && in_array($res['data']['error_response']['sub_code'],['71008','71010']) ) {
            return Normal::returnCode(Normal::SUC,$res['data']['error_response']['sub_msg']);
        }
        
        //发货退款售后
        if( isset($res['data']['error_response']['sub_code']) && in_array($res['data']['error_response']['sub_code'],['12']) &&
            isset($res['data']['error_response']['error_code']) && in_array($res['data']['error_response']['error_code'],[50001])
            ) {
            return Normal::returnCode('50001',$res['data']['error_response']['sub_msg']);
        }
        
        return Normal::returnCode(Normal::FAIL,$res['data']['error_response']['sub_msg']??'请求错误');
    }
    
    /**
     *  拉取已售后的订单
     */
    public function orderCancel( $param=[] )
    {
        $page = isset($param['page']) ? $param['page'] : 1;
        $data = [
            'order_status'      =>  5,
            'refund_status'     =>  4,
            'is_lucky_flag'     =>  0,
            'start_updated_at'  =>  $param['time']-$this->extends['interval_time'],
            'end_updated_at'    =>  $param['time'],
            'page'              =>  $page,
            'page_size'         =>  100,
            'use_has_next'      =>  'true'
        ];
        $parameter = [
            'method'    => 'orderCancel',
            'data'      => $data
        ];
        $res = $this->execute($parameter);
        if($res['code'] == Normal::FAIL ) {
            return $res;
        }
        
        $list = $res['data'];
        $binfo = Business::instance()->getUserInfoByBid($this->bid);
        if( empty($list) || empty($list['order_sn_increment_get_response']['order_sn_list']) ) {
            return Normal::returnCode(Normal::FAIL,"当前无售后订单数据");
        }
        
        $order_list_get_response = $list['order_sn_increment_get_response'];
        $order_list = $order_list_get_response['order_sn_list'];
        foreach ($order_list as $item ) 
        {
            //订单号
            $order_sn = $item['order_sn'];
            $orderLog = OrderPullLog::instance()->info(['bid'=>$this->bid,'order_sn'=>$order_sn]);
            if( empty($orderLog) ) {
                continue;
            }
            
            if( $orderLog['status'] == 2 ) {//支付成功，进行售后取消
                //调用取消订单微服务接口，更新为当前取消状态为取消成功或者取消失败
                OrderPullLog::cancelOrder([
                    'order_log_id'  => $orderLog['id'],
                    'bInfo'         => $binfo,
                    'order_sn'      => $order_sn,
                    'config'        => $this->config,
                    'reason'        => '拼多多已售后退款',
                ]);
            } else {
                //非支付成功订单不用取消,直接更新临时订单池状态为已取消
                $data = [
                    'md'            => time(),
                    'response_msg'  => '订单池处理失败3订单创建失败或4订单支付失败，直接更新当前订单池状态为6取消成功',
                    'status'        => OrderPullLog::STATUS_CANCLE_SUC
                ];
                OrderPullLog::instance()->where('id',$orderLog['id'])->update($data);
            }
        }
        
        if( $order_list_get_response['has_next'] ) {
            $this->orderCancel(['page'=>$param['page']+1,'time'=>$param['time']]);
        }
        return Normal::returnCode(Normal::SUC,"处理完成");
    }

    public function updateGoodsStatusDown( $param = [] )
    {
        if( empty($param['goods_id']) ) {
            return Normal::returnCode(Normal::FAIL,"except param goods_id");
        }
        $parameter = [
            'method'    => 'goodsSaleStatusSet',
            'data'      => [
                'goods_id'  => $param['goods_id'],
                'is_onsale' => 0,
            ]
        ];
        $res = $this->execute($parameter);

        if( $res['code'] == Normal::SUC && isset($res['data']['goods_sale_status_set_response']['is_success']) ) {
            $is_success = $res['data']['goods_sale_status_set_response']['is_success'];
            if($is_success){
                return Normal::returnCode(Normal::SUC,'上架成功');
            }
        }
        return $res;
    }

    public function updateGoodsStatusUp( $param = [] )
    {
        if( empty($param['goods_id']) ) {
            return Normal::returnCode(Normal::FAIL,"except param goods_id");
        }
        $parameter = [
            'method'    => 'goodsSaleStatusSet',
            'data'      => [
                'goods_id'  => $param['goods_id'],
                'is_onsale' => 1,
            ]
        ];
        $res = $this->execute($parameter);
        if( $res['code'] == Normal::SUC && isset($res['data']['goods_sale_status_set_response']['is_success']) ) {
            $is_success = $res['data']['goods_sale_status_set_response']['is_success'];
            if($is_success){
                return Normal::returnCode(Normal::SUC,'下架成功');
            }
        }
        return $res;
    }

    public function insertGoods( $param = [] )
    {
        $parameter = [
            'method'    => 'addGoods',
            'data'      => $param
        ];
        $res = $this->execute($parameter);
        //反写绑定pdd商品数据
        if( $res['code'] == Normal::SUC && isset($res['data']['goods_update_response']['goods_id']) ) {
            $goods_id = $res['data']['goods_update_response']['goods_id'];
            return Normal::returnCode(Normal::SUC,'新增成功',[
                'goods_id' =>  $goods_id
            ]);
        }
        return $res;
    }

    public function editGoods( $param = [] )
    {
        $parameter = [
            'method'    => 'updateGoods',
            'data'      => $param
        ];
        $res = $this->execute($parameter);
        //反写绑定pdd商品数据
        if($res['code'] == Normal::SUC){
            $is_success = $res['data']['goods_quantity_update_response']['is_success'];
            if($is_success){
                return Normal::returnCode(Normal::SUC,'更新成功');
            }
        }
        
        return Normal::returnCode(Normal::FAIL,'更新失败');
    }


    
    /**
     * 获取系统acess token
     */
    public function getAccessToken( $code = null )
    {
        if( empty($code) ) {
            return Normal::returnCode(Normal::FAIL,"获取code为空");
        }
        $parameter = [
            'client_id'     => $this->config['client_id'],
            'timestamp'     =>  time(),
            'type'          => $this->config['routeMap']['getAccessToken'],
            'code'          => $code,
        ];
        ksort($parameter);
        $signData = implode("", [
            $this->config['client_secret'],
            $this->getStr($parameter),
            $this->config['client_secret'],
        ]);
        $parameter['sign'] = strtoupper(md5($signData));
        $data = [
            'method'    => 'getAccessToken',
            'data'      => $parameter,
        ];
        return $this->execute($data);
    }
    
    /**
     * 获取店铺信息
     * @param string $token
     */
    public function getShopMallInfoByAccessToken( $token = NULL )
    {
        $parameter = [
            'client_id'     => $this->config['client_id'],
            'timestamp'     =>  time(),
            'type'          => $this->config['routeMap']['getMallInfo'],
            'access_token'  => $token,
        ];
        ksort($parameter);
        $signData = implode("", [
            $this->config['client_secret'],
            $this->getStr($parameter),
            $this->config['client_secret'],
        ]);
        $parameter['sign'] = strtoupper(md5($signData));
        $data = [
            'method'    => 'getMallInfo',
            'data'      => $parameter,
        ];
        return $this->execute($data);
    }
    
    /**
     * CURL请求
     * @param $params
     * @return mixed
     */
    public function execute( $param = [] )
    {
        if( empty($param['data']) || empty($param['method']) ) {
            return Normal::returnCode(Normal::FAIL,"except param data or method");
        }
    
        $method = $param['method'];
        if( !isset($this->routeMap[$method]) ) {
            return Normal::returnCode(Normal::FAIL,"method {$method} not configured");
        }
    
        $data           = $param['data'];
        $data['type']   = $this->routeMap[$method];
        if( !in_array($method,['getMallInfo','getAccessToken']) )
        {
            $data = $this->makeSign($data);
        }
        
        $url        = $this->url;
        $start_time = microtime(true);
        $res        = Http::apiRequest($url,$data,'post');
        $httpCode   = Http::getHttpCode();
        $response   = json_decode($res,true);
        MicroServiceLog::instance()->addLog([
            'interface_code'    => "pdd_outer_{$method}_{$this->bid}",
            'request_url'       => $url,
            'request_param'     => json_encode($data,JSON_UNESCAPED_UNICODE),
            'response_code'     => $httpCode,
            'response_data'     => $res,
            'start_time'        => microtime(true) - $start_time,
            ]);
        if( isset($response['error_response']) ) {
            $error_msg = $response['error_response']['error_msg']??'';
            return Normal::returnCode(Normal::FAIL,$error_msg,$response);
        }
        return Normal::returnCode(Normal::SUC,"获取成功",$response);
    }
    
    private function getStr( $param = [] )
    {
        $temp = [];
        foreach ($param as $k=>$v){
            $temp[] =$k.$v;
        }
        return implode("", $temp);
    }
    
    /**
     * @签名
     */
    private function makeSign( $param = [] )
    {
        //公共参数
        $common=[
            'client_id'     =>  $this->client_id,
            'access_token'  =>  $this->access_token,
            'timestamp'     =>  time(),
        ];
        $param=array_merge($param,$common);
        ksort($param);
        $signData=$this->client_secret;
        foreach ($param as $k=>$v){
            $signData.=$k.$v;
        }
        $signData.=$this->client_secret;
        $sign=strtoupper(md5($signData));
        $param['sign']=$sign;
        return $param;
    }
}